package com.wk.data4glib;

import android.util.Log;

import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


/**
 *  return mSocket != null && mSocket.isConnected();
 *  并不能完全判断 socket是否在线。我遇到这种情况，先连接正常，然后WiFi关掉，但是 isConnected仍然返回true
 *  所以最稳妥的还是 根据是否接收到数据来判断 ，如果n秒 没有接收到想要的数据 ，就认为已经断开了 。
 *
 *  另外要注意：
 *  网络的连接和断开 要放到子线程中
 *
 */
public class WkTcpTool {
    private final int SOCKET_TIME_OUT = 2* 1000;
    private InetSocketAddress socketAddress=null;
    private Socket mSocket=null;
    private BufferedWriter mBufferedWriter=null;
    private DataInputStream mDataInputStream=null;
    private boolean isRunning = false;
    private BlockingQueue<byte[]> data2SendQueue = null;
    private WkSocketCallBack wkSocketCallBack ;
    private int index = -1 ;
    private String ip ;
    private int port ;

    public WkTcpTool(String ip , int port , WkSocketCallBack wkSocketCallBack , int index) {
        this.wkSocketCallBack = wkSocketCallBack ;
        this.ip = ip ;
        this.port = port ;
        this.index = index;
        try {
            data2SendQueue = new LinkedBlockingQueue<>(Integer.MAX_VALUE) ;
            socketAddress = new InetSocketAddress(ip, port);
            mSocket = new Socket();
            initThread(); //WkTcpTool
            reConnectTcp();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initThread() {
        if (isRunning) {
            showLog("socket 无需连接，返回...");
            return;
        }
        showLog("socket 开始连接...");
        isRunning = true;
        new ReadThread().start();
        new WriteThread() .start();
    }

    private void loopSocketConnect() {
        if(mSocket==null){
            mSocket = new Socket();
        }

        if(socketAddress==null){
            socketAddress = new InetSocketAddress(ip, port);
        }

        if(data2SendQueue==null){
            data2SendQueue = new LinkedBlockingQueue<>(Integer.MAX_VALUE) ;
        }
        showLog("socket 重连中...") ;
        try {
            mSocket.connect(socketAddress, SOCKET_TIME_OUT);//连接超时时间
            if (mBufferedWriter == null) {
                mBufferedWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream(), StandardCharsets.UTF_8));
            }
            if (mDataInputStream == null) {
                mDataInputStream = new DataInputStream(mSocket.getInputStream());
            }
            showLog("socket 重连成功.mDataInputStream="+mDataInputStream  ) ;
        } catch (IOException e) {
            showLog("socket 端重连 异常..."+e.getMessage()) ;
        }

    }

    /**
     * 读取线程
     */
    private class ReadThread extends Thread {
        @Override
        public void run() {
            showLog("socket 接收线程启动...");
            while (isRunning) {
                readSocketData();

                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }


    /**
     * 必须放子线程中
     */
    public void reConnectTcp(){
       new Thread(new Runnable() {
           @Override
           public void run() {
               disconnect(); //loopSocketConnect
               loopSocketConnect();
           }
       }).start();
    }

    /**
     *  已经在子线程中 执行关闭。 主线程可以直接调用
     */
    public void closeAllConnection() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                disconnect(); //closeAllConnection
                isRunning = false;
            }
        }).start();

    }


    public void readSocketData() {

         if(mDataInputStream==null){
            //showLog("读取线程 mDataInputStream 为空");
            return;
        }
        try {
            //showLog("读取中....available="+ mDataInputStream.available());
            if (  mDataInputStream.available() > 0) {
                byte[] recData = new byte[mDataInputStream.available()];
                int readSize = mDataInputStream.read(recData);

                if(wkSocketCallBack!=null){
                    wkSocketCallBack.onGetData(recData ,index);
                }

            }
        } catch (IOException e) {
            showLog("读取异常~~");

        }
    }


    public void sendDataBytes(byte[] data){
        try {
            if(data2SendQueue!=null){
                data2SendQueue.put(data);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private class WriteThread extends Thread {
        @Override
        public void run() {
            showLog("socket 发送线程启动...");
            while (isRunning) {

                if(data2SendQueue!=null){
                    byte [] data=   data2SendQueue.poll();
                    if(data!=null){
                        realSend(data) ;
                    }
                }

                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    private void realSend(final byte[] bytes) {
        if(mSocket==null){
            showLog("realSend mSocket ==null null==");
            return;
        }

        if (bytes == null || bytes.length == 0) {
            return;
        }
       // showLog("realSend  =="+ WkByteBitTools.byte2HexStr(bytes));
        try {
            OutputStream os = mSocket.getOutputStream();
            if(os!=null){
                os.write(bytes);
                os.flush();
            }

        } catch (Exception e) {
            //showLog("发送线程出现异常="+ e.getMessage());
        }
    }




    public void disconnect() {
        try {
            if(mBufferedWriter!=null){
                mBufferedWriter.close();
                mBufferedWriter=null;
            }

            if(mDataInputStream!=null){
                mDataInputStream.close();
                mDataInputStream=null;
            }

            if(data2SendQueue!=null){
                data2SendQueue.clear();
                data2SendQueue=null ;
            }

            if(mSocket!=null){
                mSocket.close();
                mSocket=null;
            }

            socketAddress=null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        showLog("socket 关闭完成...");
    }

    private void showLog(String msg){
        Log.i(index+"---->"+this.getClass().getSimpleName() ,msg) ;
    }

}